<?php

use \GatewayWorker\Lib\Gateway;  

require_once dirname(__DIR__) . '/public.class.model.php';
class Room_Model extends Public_Model
{
	
	/***************************
			common_function	
	***************************/
	
	
	/*
		断线
	*/
	public function userDisconnected($arrData)
	{
		if(!isset($arrData['gaming_roomid']) || trim($arrData['gaming_roomid']) == G_CONST::EMPTY_STRING)
		{
			return false;
		}
		if(!isset($arrData['account_id']) || trim($arrData['account_id']) == G_CONST::EMPTY_STRING)
		{
			return false;
		}
		
		$room_id 		= $arrData['gaming_roomid'];
		$account_id 	= $arrData['account_id'];
		$client_id 		= $arrData['client_id'];

		if($this->queryOnlineStatus($room_id, $account_id)){
			$this->writeLog("[$room_id]($account_id) still in room");
			return true;
		}
		
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);

		//没开局玩过的用户离线，自动从房间中退出
		if($this->queryTicketChecked($room_id, $account_id) == 0){
			$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
			$zrem_result = $Redis_Model->zremSet($RoomSequence_Key,array($account_id));

			$account_status = Game::AccountStatus_Initial;
		} else {
			$account_status = $this->queryAccountStatus($room_id, $account_id);

			if($account_status == Game::AccountStatus_Ready){	//准备状态下断线， 变为未准备
				
				$account_status = Game::AccountStatus_Notready;
			}
		}

		$this->updateAccountStatus($room_id, $account_id, $account_status);
		$this->writeLog("[$room_id]($account_id) leave room");
		
		//获取房间状态
		$room_status = $this->queryRoomStatus($room_id);
		if($room_status === Redis_CONST::DATA_NONEXISTENT || $room_status == Game::RoomStatus_Closed ){	//房间已经废弃或未激活
			return true;
		}

		if($room_status == Game::RoomStatus_Waiting)
		{
			$ready_count = $this->queryReadyCount($room_id);
			if($ready_count < 2){
				//取消倒计时
				$this->deleteRoomTimer($room_id);
				$arr = array("result"=>0,"operation"=>"CancelStartLimitTime","data"=>array(),"result_message"=>"取消开局倒计时");
				$this->pushMessageToGroup($room_id, $arr);
			} else {
				$this->startGame($room_id);
			}
		}

		//判断是否全部人离线
		$clients_of_groupid = Gateway::getClientSessionsByGroup($room_id);
		if(count($clients_of_groupid) == 0)
		{
			$this->setupClearRoomPassiveTimer($room_id);
		}

		return true; 
	}
	
	
	
	/***************************
			logic_function	
	***************************/
	
	/*
		创建房间
	*/
	public function createRoom($arrData)
	{
		$timestamp = time();
		$result = array();
		$return = array();
		
		$data 			= $arrData['data'];
		$operation 		= $arrData['operation'];
		$account_id 	= $arrData['account_id'];
		$client_id 		= $arrData['client_id'];
		
		if(!isset($data['data_key']) || trim($data['data_key']) == G_CONST::EMPTY_STRING)
		{
			$this->logMessage('error', "function(createRoom):lack of data_key"." in file".__FILE__." on Line ".__LINE__);
			return $this->_missingPrameterArr($operation,"data_key");
		}

		if(!isset($data['ticket_count']))
		{
			$this->logMessage('error', "function(createRoom):lack of ticket_count"." in file".__FILE__." on Line ".__LINE__);
			return $this->_missingPrameterArr($operation,"ticket_count");
		}	

		$session 		= $arrData['session'];
		$Verification_Model = Verification_Model::getModelObject();
		if(false == $Verification_Model->checkRequestSession($account_id,$session))
		{
			return OPT_CONST::NO_RETURN;
		}
        //获取随机房间号
        $newRoomNumber = $this->getNewRoomNumber();
		$data_key = $data['data_key'];
		$spend_ticket_count = $data['ticket_count'];
		$total_num = Config::GameNum_EachRound * $spend_ticket_count;

		$banker_mode = Game::BankerMode_FreeGrab;	//默认自由抢庄

		//庄家类型
		if(isset($data['banker_mode']) && in_array($data['banker_mode'], [Game::BankerMode_FreeGrab,Game::BankerMode_FixedBanker]))
		{
			$banker_mode = $data['banker_mode'];
		}
		else
		{
			$this->writeLog("function(createRoom):用户".$account_id." banker_mode error："." in file".__FILE__." on Line ".__LINE__);
			return array("result"=>"-1","operation"=>$operation,"data"=>$result,"result_message"=>"错误模式"); 
		}

		//二八杠规则
		if(isset($data['rule_type']) && in_array($data['rule_type'], [1,2,3]))
		{
			$rule_type = $data['rule_type'];
		}
		else
		{
			$this->writeLog("function(createRoom):用户".$account_id." rule_type error："." in file".__FILE__." on Line ".__LINE__);
			return array("result"=>"-1","operation"=>$operation,"data"=>$result,"result_message"=>"错误规则"); 
		}
        if(!isset($data['client_name'])){
            $data['client_name'] = "wechat";
        }
        if(!isset($data['client_type'])){
            $data['client_type'] = "wechat";
        }
        if(!isset($data['daikai_id'])){
            $data['daikai_id'] = 0;
        }
		//获取维护公告
		$alert_type = -1;
		$alert_text = "";
		$announcement_result = $this->getGameAnnouncement($account_id);
		if(is_array($announcement_result))
		{
			$alert_type = $announcement_result['alert_type'];
			$alert_text = $announcement_result['alert_text'];
		}
		if($alert_type == 4)
		{
			$result['alert_type'] = $alert_type;
			return array("result"=>"-1","operation"=>$operation,"data"=>$result,"result_message"=>$alert_text); 
		}

		$banker_score = 0;
		$chip_type = 1;
		if($banker_mode == Game::BankerMode_FixedBanker)
		{
			$banker_score = Config::BankerScore_1;
			//庄家类型
			if(isset($data['banker_score_type']) && in_array($data['banker_score_type'], [1,2,3,4]))
			{
				$banker_score_type = $data['banker_score_type'];
			}
			
			//庄家类型
			switch ($banker_score_type) {
				case '1':
					$banker_score = Config::BankerScore_1;
					break;
				case '2':
					$banker_score = Config::BankerScore_2;
					break;
				case '3':
					$banker_score = Config::BankerScore_3;
					break;
				case '4':
					$banker_score = Config::BankerScore_4;
					break;
				default:
					$banker_score = 0;
					break;
			}
		} else if($banker_mode == Game::BankerMode_FreeGrab){
			if(isset($data['chip_type']) && in_array($data['chip_type'], [1,2,3]))
			{
				$chip_type = $data['chip_type'];
			}
		}



		$MMYSQL = $this->initMysql();
		//判断房卡余额
		$my_ticket_count = $MMYSQL->select("ticket_count")->from("room_ticket")->where("account_id=".$account_id)->single();
		$this->writeLog("($account_id) 牌券:" . $my_ticket_count);
		if($my_ticket_count >= $spend_ticket_count){

		} else {
			$this->writeLog("($account_id) 牌券不足");
			$result['alert_type'] = 1;	//1房卡不足
			return array("result"=>"1","operation"=>$operation,"data"=>$result,"result_message"=>"房卡不足"); 
		}

		//判断房间申请记录是否存在
		$room_where = 'data_key="'.$data_key.'"';
		$room_sql = 'select room_id,room_number,account_id,is_close from '.Room.' where '.$room_where;
		$room_query = $MMYSQL->query($room_sql);
		if(!is_array($room_query) || count($room_query) == 0 )
		{
			$room_aid = $account_id;
			$is_close = G_CONST::IS_FALSE;
			
			$r_array['create_time'] = $timestamp;
			$r_array['create_appid'] = "aid_".$account_id;
			$r_array['update_time'] = $timestamp;
			$r_array['update_appid'] = "aid_".$account_id;
			$r_array['is_delete'] = G_CONST::IS_FALSE;
			$r_array['data_key'] = $data_key;
			$r_array['account_id'] = $room_aid;
			$r_array['is_close'] = G_CONST::IS_FALSE;
            $r_array['new_room_number'] = $newRoomNumber;
            $r_array['client_name'] = $data['client_name'];
            $r_array['client_type'] = $data['client_type'];
			$r_array['daikai_id'] = $data['daikai_id'];
			$room_id = $MMYSQL->insertReturnID(Room,$r_array);
			if($room_id > 0)
			{
                $room_number = 100000 + $room_id * 10 + mt_rand(1,9);
			}
			else
			{
				$this->logMessage('error', "function(createRoom):用户".$account_id." 创建房间失败："." in file".__FILE__." on Line ".__LINE__);
				return array("result"=>"-1","operation"=>$operation,"data"=>$result,"result_message"=>"创建房间失败"); 
			}

			$num_updateSql = 'update '.Room.' set room_number="'.$room_number.'" where room_id='.$room_id;
			$num_updateQuery = $MMYSQL->query($num_updateSql);
		}
		else
		{
			$room_id = $room_query[0]['room_id'];
			$room_number = $room_query[0]['room_number'];
			$room_aid = $room_query[0]['account_id'];
			$is_close = $room_query[0]['is_close'];
		}
		
		//添加房间信息到redis
		$Redis_Model = Redis_Model::getModelObject();
		
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$r_mkv[Redis_Const::Room_Field_Number] = $room_number;	//房间号
		$r_mkv[Redis_Const::Room_Field_GameRound] = 1;			//游戏轮数
		$r_mkv[Redis_Const::Room_Field_GameNum] = 0;			//游戏局数
		//$r_mkv[Redis_Const::Room_Field_PeopleNum] = 0;			//游戏人数
		$r_mkv[Redis_Const::Room_Field_Status] = Game::RoomStatus_Waiting;				//房间状态，1等待、2进行中、3关闭
		$r_mkv[Redis_Const::Room_Field_ActiveUser] = -1;		//当前操作用户
		$r_mkv[Redis_Const::Room_Field_ActiveTimer] = -1;		//当前生效timer
		$r_mkv[Redis_Const::Room_Field_TotalNum] = $total_num;		//每轮总局数
		$r_mkv[Redis_Const::Room_Field_TicketCount] = $spend_ticket_count;		//每轮消耗房卡数量
		$r_mkv[Redis_Const::Room_Field_Creator] = $account_id;		//创建用户
		$r_mkv[Redis_Const::Room_Field_Scoreboard] = "";		//积分榜
		$r_mkv[Redis_Const::Room_Field_StartTime] = -1;

		$r_mkv[Redis_Const::Room_Field_BankerMode] = $banker_mode;		//庄家类型
		$r_mkv[Redis_Const::Room_Field_RuleType]   = $rule_type;		//规则类型

		$r_mkv[Redis_Const::Room_Field_BankerScore] = $banker_score;	//上庄分数
		$r_mkv[Redis_Const::Room_Field_ChipType] = $chip_type;	//自由抢庄筹码类型

		$r_mkv[Redis_Const::Room_Field_ReadyTime] = -1;  //修复建房后首次开局前没有倒计时的bug
        $r_mkv[Redis_CONST::Room_Field_NewNumber] = $newRoomNumber;
		$mset_result = $Redis_Model->hmsetField($Room_Key,$r_mkv);
        $RedisLog_Model = Redis_Model::getModelObjectLogs();
        $RedisLog_Model->hmsetField(Redis_CONST::Room_New_Key,[$newRoomNumber=>json_encode(["room_number"=>$room_number,"game_type"=>Game::Game_Type, "create_time"=>date('Y-m-d H:i:s',$timestamp),"client_name"=>$data['client_name']])]);

        if(Game::PaymentType_Creator == Config::Ticket_Mode)
		{
			//扣除房卡
			$this->balanceTicket($room_id, $account_id, $spend_ticket_count);
		}
		
		$result['room_id'] = $room_id;
		$result['room_number'] = $room_number;
		$result['is_close'] = $is_close;
		
		$this->writeLog("[$room_id]($account_id) 创建房间");

		$this->setupClearRoomPassiveTimer($room_id);
		return array("result"=>OPT_CONST::SUCCESS,"operation"=>$operation,"data"=>$result,"result_message"=>"创建房间");  
	}
    public function getNewRoomNumber(){
        $ti = microtime();
        list($s,$m) = explode(" ", $ti);
        $newRoomNumber = substr($m + substr($s,2), 4);
        if ($newRoomNumber <= 100000) $newRoomNumber += 100000;
        $RedisLog_Model = Redis_Model::getModelObjectLogs();
        if ($RedisLog_Model->hexistsField('RoomNumber',$newRoomNumber) == Redis_CONST::Key_Nonexistent){
            return $newRoomNumber;
        }else{
            return $this->getNewRoomNumber();
        }
    }
	/*
		进入房间
	*/
	public function joinRoom($arrData)
	{
		$result = array();
		$return = array();
		
		$data 			= $arrData['data'];
		$operation 		= $arrData['operation'];
		$account_id 	= $arrData['account_id'];
		$client_id 		= $arrData['client_id'];

		$session 		= $arrData['session'];
		$Verification_Model = Verification_Model::getModelObject();
		if(false == $Verification_Model->checkRequestSession($account_id,$session))
		{
			return OPT_CONST::NO_RETURN;
		}
		
		if(!(isset($data['room_number'])&& $data['room_number'] > 0) )
		{
			$this->logMessage('error', "function(joinRoom):lack of room_number"." in file".__FILE__." on Line ".__LINE__);
			return $this->_missingPrameterArr($operation,"room_number");
		}
		
		$room_number = $data['room_number'];
		
		$MMYSQL = $this->initMysql();
		//判断房间申请记录是否存在
		$room_where = 'room_number='.$room_number;
		$room_sql = 'select room_id,account_id,is_close from '.Room.' where '.$room_where;
		$room_row = $MMYSQL->row($room_sql);
		if(!$room_row){
			$this->logMessage('error', "function(joinRoom):room($room_number) not exist"." in file".__FILE__." on Line ".__LINE__);
			return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>$result,"result_message"=>"房间不存在");  
		} else {
			$room_id = $room_row['room_id'];
			if($room_row['is_close'])
			{
				$result['room_status'] = 4;
				return array("result"=>"0","operation"=>$operation,"data"=>$result,"result_message"=>"房间已关闭"); 
			}
		}
		
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		
		//总分数
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$RoomScore_Field_User = strtr(Redis_Const::RoomScore_Field_User, $replyArr);
			
		$rsSeq_score = $Redis_Model->getZscore($RoomSequence_Key,$account_id);
		//判断用户是否已加入房间
		if(Redis_CONST::DATA_NONEXISTENT !== $rsSeq_score)		//已加入
		{
			//获取分数
			$rScore_score = $Redis_Model->hgetField($RoomScore_Key,$RoomScore_Field_User);
			//获取用户所在位置
			$serial_num = $rsSeq_score;

			$account_status = $this->queryAccountStatus($room_id, $account_id);
		}
		else	//未加入
		{
			//判断游戏人数
			$user_count = 0;
			//获取房间所有用户
			$sset_array['key'] = $RoomSequence_Key;
			$sset_array['WITHSCORES'] = "WITHSCORES";
			$gamer_query = $Redis_Model->getSortedSetLimitByAry($sset_array);
			if(Redis_CONST::DATA_NONEXISTENT !== $gamer_query)
			{
				$user_count = count($gamer_query);
			}
			if($user_count >= Config::GameUser_MaxCount)
			{
				$this->writeLog("[$room_id]($account_id) joinRoom 人数已满");
				$result['alert_type'] = 2;
				return array("result"=>"1","operation"=>$operation,"data"=>$result,"result_message"=>"房间人数已满");  
			}
			
			$serial_num = -1;
			for($i=1;$i<=Config::GameUser_MaxCount;$i++)
			{
				if(array_search($i,$gamer_query) === false)
				{
					$serial_num = $i;
					break;
				}
			}
			
			if($serial_num == -1)
			{
				$this->logMessage('error', "function(joinRoom):serial_num($serial_num) 无法找到空桌位"." in file".__FILE__." on Line ".__LINE__);
				return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>$result,"result_message"=>"数据错误");  
			}


			$success = $this->joinRoomTransaction($room_id,$account_id,$serial_num);
			if(!$success){
				$this->writeLog("并发 join room，忽略。room id:".$room_id.",serial_num:".$serial_num.",account_id:".$account_id."。in file".__FILE__." on Line ".__LINE__);
				$result['alert_type'] = 2;
				return array("result"=>"1","operation"=>$operation,"data"=>$result,"result_message"=>"房间人数已满"); 
			}

			//$rSeq_mkv[$serial_num] = $account_id;
			//$zadd_result = $Redis_Model->zaddSet($RoomSequence_Key,$rSeq_mkv);
			
			//添加默认分数
			$rScore_score = 0;
			$rScore_mkv[$RoomScore_Field_User] = $rScore_score;
			$hmset_result = $Redis_Model->hmsetField($RoomScore_Key,$rScore_mkv);

			//首次进房初始状态
			$account_status =  Game::AccountStatus_Initial;
			$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
			$mkv[$account_id] = $account_status;
			$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);

		}

		//绑定用户UID
		$room_aid = strtr(Game::RoomUser_UID, $replyArr);
		Gateway::bindUid($client_id, $room_aid);
		Gateway::joinGroup($client_id, $room_id);
		
		$game_num = $this->queryGameNumber($room_id);
		$room_status = $this->queryRoomStatus($room_id);
		$room_ary['room_id'] = $room_id;
		$room_ary['room_number'] = $room_number;
		$room_ary['room_status'] = $room_status;
		$room_ary['account_score'] = $rScore_score;
		$room_ary['account_status'] = $account_status;
		$room_ary['online_status'] = $this->queryOnlineStatus($room_id, $account_id);
		$room_ary['serial_num'] = $serial_num;
		$room_ary['game_num'] = $game_num;
		$room_ary['scoreboard'] = $this->queryScoreboard($room_id);
		$room_ary['total_num'] = $this->queryTotalNum($room_id);

		$setting = $this->queryRoomSetting($room_id);
		$room_ary['chip_type'] = isset($setting[Redis_Const::Room_Field_ChipType])?$setting[Redis_Const::Room_Field_ChipType]:1;
		$banker_mode = $setting[Redis_CONST::Room_Field_BankerMode];
		$room_ary['banker_mode'] = $banker_mode;

		$rule_type = $setting[Redis_CONST::Room_Field_RuleType];
		$room_ary['rule_type'] = $rule_type;
        $room_ary['creator_id'] = $setting[Redis_CONST::Room_Field_Creator];
		$limit_score = $setting[Redis_CONST::Room_Field_BankerScore];

		$circle = $this->queryCircle($room_id);
		$room_ary['circle'] = $circle > 0 ? $circle : -1;
		$room_ary['position_info'] = $this->getPositionInfo($room_id, $account_id, $circle);

		$room_ary['first_half_cards'] = array();
		if($circle >= Game::Circle_Pause){
			$Cards = $this->queryCardInfo($room_id);
			if(count($Cards)==20){
				$room_ary['first_half_cards'] = array_slice($Cards, 0, 8);
			}
		}

		$room_ary['can_break'] = 0;
		$banker_id = $this->queryBanker($room_id);
		$banker_score=$this->queryAccountScore($room_id, $banker_id);
		$room_ary['can_break'] = $banker_mode == Game::BankerMode_FixedBanker && ($banker_score >= 2 * $this->queryBankerScore($room_id)) && $limit_score!=0;

		//推送房间信息
		$room_return = array("result"=>OPT_CONST::SUCCESS,"operation"=>$operation,"data"=>$room_ary,"result_message"=>"入房成功");
		$this->pushMessageToCurrentClient($room_return);
		
		//返回所有玩家状态给进房玩家
		$allGamer = $this->getGamerInfo($room_id);
		if(is_array($allGamer))
		{
			$currentGamer_return = array("result"=>OPT_CONST::SUCCESS,"operation"=>"AllGamerInfo","data"=>$allGamer,"result_message"=>"所有玩家状态");
			$this->pushMessageToCurrentClient($currentGamer_return);
		}
		
		//推送当前玩家状态给其他玩家
		$currentGamer = $this->getGamerInfo($room_id,$account_id);
		if(is_array($currentGamer))
		{
			$currentGamer_return = array("result"=>OPT_CONST::SUCCESS,"operation"=>"UpdateGamerInfo","data"=>$currentGamer,"result_message"=>"某玩家状态");
			$this->pushMessageToGroup($room_id, $currentGamer_return, $client_id);
		}

		//判断是否第一个进房
		$clients_of_groupid = Gateway::getClientSessionsByGroup($room_id);
		if(count($clients_of_groupid) == 1)
		{
			if($circle == Game::Circle_Bet || $circle == Game::Circle_Bet2){
				$this->setupBetPassiveTimer($room_id);
			} else if($circle == Game::Circle_Pause) {
				$this->setupNextHalfPassiveTimer($room_id);
			}
		}

		//显示房间目前的倒计时
		$this->showRoomCountdown($room_id);

		//保存用户当前房间,用户ID
		$_SESSION['gaming_roomid'] = $room_id;
		$_SESSION['account_id'] = $account_id;

		$this->writeLog("[$room_id]($account_id) 进入房间");
		return OPT_CONST::NO_RETURN;
	}

	public function getPositionInfo($room_id, $account_id, $circle){
		$position_info = array();
		$card_info = array();
		$card_value = 0;
		if($circle == Game::Circle_Show){
			$Cards = $this->queryCardInfo($room_id);
			if(count($Cards)==20){
				for ($i=0; $i < 4; $i++) { 
					$card_info  =  array($Cards[2*$i], $Cards[2*$i+1]);
					$card_value = $this->caculateCardValue($card_info, $room_id);
					$chip =   $this->queryChip($room_id, $i, $account_id);
					$position_info[$i] = array(
						'card_info' => $card_info,
						'card_value'=> $card_value,
						'chip' => $chip
						);
				}
			}

		} else if($circle == Game::Circle_Show2){
			$Cards = $this->queryCardInfo($room_id);
			if(count($Cards)==20){
				for ($i=0; $i < 4; $i++) { 
					$card_info  =  array($Cards[2*$i+8], $Cards[2*$i+9]);
					$card_value = $this->caculateCardValue($card_info, $room_id);
					$chip =   $this->queryChip($room_id, $i, $account_id);
					$position_info[$i] = array(
						'card_info' => $card_info,
						'card_value'=> $card_value,
						'chip' => $chip
						);
				}
			}

		} else if(in_array($circle, [Game::Circle_Bet, Game::Circle_Bet2, Game::Circle_Deal, Game::Circle_Deal2])){
			for ($i=0; $i < 4; $i++) { 
				$chip =   $this->queryChip($room_id, $i, $account_id);
				$position_info[$i] = array(
					'card_info' => $card_info,
					'card_value'=> $card_value,
					'chip' => $chip
					);
			}
		}
		return $position_info;
	}

	/*
		获取房间所有用户
	*/
	protected function getGamerInfo($room_id,$account_id=-1)
	{
		$result = array();
		
		$Redis_Model = Redis_Model::getModelObject();
		$MMYSQL = $this->initMysql();
		
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);

		//房间玩家集合
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		
		//获取房间所有用户
		$sset_array['key'] = $RoomSequence_Key;
		$sset_array['WITHSCORES'] = "WITHSCORES";
		$gamer_query = $Redis_Model->getSortedSetLimitByAry($sset_array);
		if(Redis_CONST::DATA_NONEXISTENT !== $gamer_query)
		{
			foreach($gamer_query as $gamer_id=>$serial_num)
			{
				//获取玩家信息
				$account_where = 'account_id="'.$gamer_id.'"';
				$account_sql = 'select nickname,headimgurl from '.WX_Account.' where '.$account_where;
				$account_query = $MMYSQL->query($account_sql);
				if(!is_array($account_query) || count($account_query) == 0 )
				{
					$this->logMessage('error', "function(getGamerInfo):account($account_id) not exist"." in file".__FILE__." on Line ".__LINE__);
					return false;
				}
				$info['serial_num'] = $serial_num;
				$info['account_id'] = $gamer_id;
				$info['nickname'] = $account_query[0]['nickname'];
				$info['headimgurl'] = $account_query[0]['headimgurl'];
				
				
				//获取玩家当前积分
				$rScore_score = $this->queryAccountScore($room_id, $gamer_id);
				if(Redis_CONST::DATA_NONEXISTENT === $rScore_score)
				{
					$this->logMessage('error', "function(getGamerInfo):account($account_id) score not exist"." in file".__FILE__." on Line ".__LINE__);
					return false;
				}
				$info['account_score'] = $rScore_score;
				
				//获取玩家当前状态
				$rStatus = $this->queryAccountStatus($room_id, $gamer_id);
				if(Redis_CONST::DATA_NONEXISTENT === $rStatus)
				{
					$this->logMessage('error', "function(getGamerInfo):account($account_id) status not exist"." in file".__FILE__." on Line ".__LINE__);
					return false;
				}
				$info['account_status'] = $rStatus;
				$info['online_status'] = $this->queryOnlineStatus($room_id, $gamer_id);
				$info['ticket_checked'] = $this->queryTicketChecked($room_id, $gamer_id);

				//是否庄家
				$is_banker = G_CONST::IS_FALSE;
				$banker_id = $this->queryBanker($room_id);
				if($banker_id == $gamer_id)
				{
					$is_banker = G_CONST::IS_TRUE;
				}
				$info['is_banker'] = $is_banker;

				if($account_id == $gamer_id)
				{
					return $info;
				}
				
				$result[] = $info;
			}
		}
		
		return $result;
	}
	

	protected function joinRoomTransaction($room_id,$account_id,$serial_num)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$key = strtr(Redis_Const::RoomSequence_Key, $replyArr);

		$redisAuth = $Redis_Model->pingRedisAuth();
		if($redisAuth === G_CONST::EMPTY_STRING || !is_object($redisAuth))
		{
			$this->logMessage('error', "function(joinRoomTransaction):redisAuth is empty string"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

	    $success = false;
	    $options = array(
	        'cas'   => true,    // Initialize with support for CAS operations
	        'watch' => $key,    // Key that needs to be WATCHed to detect changes
	        'retry' => 3,       // Number of retries on aborted transactions, after
	                            // which the client bails out with an exception.
	    );

	    $redisAuth->transaction($options, function ($tx) use ($key,$serial_num,$account_id, &$success) {
	    	$where = array('withscores'=>TRUE);
	    	$result = $tx->zrevrangebyscore($key,$serial_num,$serial_num,$where);
	        if(is_array($result) && count($result) == 0) {
	        	$tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
				$zadd_result = $tx->zadd($key,$serial_num,$account_id);
	            $success =  true;
	        } else {
	        	//echo "room_status != 1".PHP_EOL;
	            $this->logMessage('error', "function(joinRoomTransaction):zrevrangebyscore error "." in file".__FILE__." on Line ".__LINE__);
	        	$success =  false;
	        }
	    });
	    return $success;
	}


	/*
		刷新房间
	*/
	public function pullRoomInfo($arrData)
	{
		$timestamp = time();
		$result = array();
		$return = array();
		
		$data 			= $arrData['data'];
		$operation 		= $arrData['operation'];
		$account_id 	= $arrData['account_id'];
		$client_id 		= $arrData['client_id'];

		$session 		= $arrData['session'];
		$Verification_Model = Verification_Model::getModelObject();
		if(false == $Verification_Model->checkRequestSession($account_id,$session))
		{
			return OPT_CONST::NO_RETURN;
		}
		
		if(!(isset($data['room_id'])&& $data['room_id'] > 0) )
		{
			$this->logMessage('error', "function(pullRoomInfo):lack of room_id"." in file".__FILE__." on Line ".__LINE__);
			return $this->_missingPrameterArr($operation,"room_id");
		}
		
		$room_id = $data['room_id'];
		$MMYSQL = $this->initMysql();
		
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		
		//总分数
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$RoomScore_Field_User = strtr(Redis_Const::RoomScore_Field_User, $replyArr);
			
		$rsSeq_score = $Redis_Model->getZscore($RoomSequence_Key,$account_id);
		//判断用户是否已加入房间
		if(Redis_CONST::DATA_NONEXISTENT !== $rsSeq_score)		//已加入
		{
			//获取分数
			$rScore_score = $Redis_Model->hgetField($RoomScore_Key,$RoomScore_Field_User);
			//获取用户所在位置
			$serial_num = $rsSeq_score;

			$account_status = $this->queryAccountStatus($room_id, $account_id);
		}
		else	//未加入
		{
			$this->logMessage('error', "function(pullRoomInfo):account($account_id) not join room"." in file".__FILE__." on Line ".__LINE__);
			return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>$result,"result_message"=>"用户未加入房间"); 
		}

		//绑定用户UID
		$room_aid = strtr(Game::RoomUser_UID, $replyArr);

		$game_num = $this->queryGameNumber($room_id);
		$room_status = $this->queryRoomStatus($room_id);
		$room_ary['room_id'] = $room_id;
		$room_ary['room_status'] = $room_status;
		$room_ary['account_score'] = $rScore_score;
		$room_ary['account_status'] = $account_status;
		$room_ary['online_status'] = $this->queryOnlineStatus($room_id, $account_id);
		$room_ary['serial_num'] = $serial_num;
		$room_ary['game_num'] = $game_num;
		$room_ary['scoreboard'] = $this->queryScoreboard($room_id);
		$room_ary['total_num'] = $this->queryTotalNum($room_id);

		$setting = $this->queryRoomSetting($room_id);
		$room_ary['chip_type'] = isset($setting[Redis_Const::Room_Field_ChipType])?$setting[Redis_Const::Room_Field_ChipType]:1;
		$banker_mode = $setting[Redis_CONST::Room_Field_BankerMode];
		$room_ary['banker_mode'] = $banker_mode;

		$rule_type = $setting[Redis_CONST::Room_Field_RuleType];
		$room_ary['rule_type'] = $rule_type;

		$circle = $this->queryCircle($room_id);
		$room_ary['circle'] = $circle > 0 ? $circle : -1;
		$room_ary['position_info'] = $this->getPositionInfo($room_id, $account_id, $circle);

		$room_ary['first_half_cards'] = array();
		if($circle >= Game::Circle_Pause){
			$Cards = $this->queryCardInfo($room_id);
			if(count($Cards)==20){
				$room_ary['first_half_cards'] = array_slice($Cards, 0, 8);
			}
		}
				
		//返回所有玩家状态给进房玩家
		$allGamer = $this->getGamerInfo($room_id);
		if(!is_array($allGamer))
		{
			$this->logMessage('error', "function(pullRoomInfo):room($room_id) no player"." in file".__FILE__." on Line ".__LINE__);
			return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>$result,"result_message"=>"房间没有其他用户"); 
		}

		$pull_return = array("result"=>OPT_CONST::SUCCESS,"operation"=>$operation,"data"=>$room_ary,"result_message"=>"拉取房间信息","all_gamer_info"=>$allGamer);
		$this->pushMessageToCurrentClient($pull_return);

		$this->logMessage('error', "function(pullRoomInfo):用户 $account_id 拉取房间 $room_id 信息"." in file".__FILE__." on Line ".__LINE__);
		
		return OPT_CONST::NO_RETURN;
	}



	/*
		进房之前的查询
	*/
	public function prepareJoinRoom($arrData)
	{
		$result = array();
		
		$data 			= $arrData['data'];
		$operation 		= $arrData['operation'];
		$account_id 	= $arrData['account_id'];

		$session 		= $arrData['session'];
		$Verification_Model = Verification_Model::getModelObject();
		if(false == $Verification_Model->checkRequestSession($account_id,$session))
		{
			return OPT_CONST::NO_RETURN;
		}
		
		if(!(isset($data['room_number'])&& $data['room_number'] > 0) )
		{
			$this->logMessage('error', "function(PrepareJoinRoom):lack of room_number"." in file".__FILE__." on Line ".__LINE__);
			return $this->_missingPrameterArr($operation,"room_number");
		}
		
		$room_number = $data['room_number'];

		//判断房间是否存在
		$MMYSQL = $this->initMysql();
		$room_sql = 'select room_id,account_id,is_close from '.Room.' where room_number='.$room_number;
		$room_row = $MMYSQL->row($room_sql);
		if(!$room_row){
			$this->logMessage('error', "function(joinRoom):room($room_number) not exist"." in file".__FILE__." on Line ".__LINE__);
			return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>$result,"result_message"=>"房间不存在");  
		} else {
			$room_id = $room_row['room_id'];
			if($room_row['is_close']){
				$result = array('room_status'=>4);
				return array("result"=>0, "operation"=>$operation,"data"=>$result,"result_message"=>"房间已关闭"); 
			}
		}

		//房间参数
		$user_count = 0;
		$alert_text = "";
		
		$room_ary['user_count'] = $user_count;
		$room_ary['alert_text'] = $alert_text;
		$room_ary['room_status'] = $this->queryRoomStatus($room_id);

		$room_rule = $this->queryRoomRule($room_id); 
		$room_ary['ticket_count'] = $room_rule['ticket_count'];
		$room_ary['banker_score_type'] = $room_rule['banker_score_type'];
		$room_ary['banker_mode'] = $room_rule['banker_mode'];
		$room_ary['rule_type'] = $room_rule['rule_type'];
		$room_ary['chip_type'] = $room_rule['chip_type'];
        $setting = $this->queryRoomSetting($room_id);
        $room_ary['creator_id'] = $setting[Redis_CONST::Room_Field_Creator];
		//获取维护公告
		$alert_type = -1;
		$alert_text = "";
		$announcement_result = $this->getGameAnnouncement($account_id);
		if(is_array($announcement_result))
		{
			$alert_type = $announcement_result['alert_type'];
			$alert_text = $announcement_result['alert_text'];
		}
		if($alert_type == 4)
		{
			$room_ary['alert_type'] = $alert_type;
			return array("result"=>"1","operation"=>$operation,"data"=>$room_ary,"result_message"=>$alert_text); 
		}

		//判断房卡余额
		if(Game::PaymentType_AA == Config::Ticket_Mode)
		{
			$spend_ticket_count = $this->queryTicketCount($room_id);
			$my_ticket_count = $MMYSQL->select("ticket_count")->from("room_ticket")->where("account_id=".$account_id)->single();
			$this->writeLog("[$room_id]($account_id) 牌券:" . $my_ticket_count);
			if($my_ticket_count >= $spend_ticket_count || $this->queryTicketChecked($room_id, $account_id) >= 1){
				
			} else {
				$this->writeLog("[$room_id]($account_id) 牌券不足");
				$room_ary['alert_type'] = 1;
				return array("result"=>"1","operation"=>$operation,"data"=>$room_ary,"result_message"=>"房卡不足"); 
			}
		}

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);

		//房间人
		$room_users = array();
		$is_member = false;
		//获取房间所有用户
		$sset_array['key'] = $RoomSequence_Key;
		$gamer_query = $Redis_Model->getSortedSetLimitByAry($sset_array);
		if(Redis_CONST::DATA_NONEXISTENT !== $gamer_query)
		{
			foreach($gamer_query as $gamer_id)
			{
				//获取玩家信息
				$account_where = 'account_id="'.$gamer_id.'"';
				$account_sql = 'select account_id,nickname from '.WX_Account.' where '.$account_where;
				$row = $MMYSQL->row($account_sql);
				if($row){
					$room_users[] = $row['nickname'];
					$user_count++;
					if($row['account_id'] == $account_id){
						$is_member = true;
					}
				} 
			}
		}

		if($user_count == 0 || $is_member){
			$alert_text = "";
		} else {
			if($user_count >= Config::GameUser_MaxCount){
				$this->writeLog("[$room_id]($account_id) PrepareJoinRoom:room($room_number) 人数已满");
				$room_ary['alert_type'] = 2;
				return array("result"=>"1","operation"=>$operation,"data"=>$room_ary,"result_message"=>"房间人数已满");  
			} 
			$user_str = implode("、", $room_users);
			$alert_text = "房间中有".$user_str."，是否加入？";
		}


		$room_ary['user_count'] = $user_count;
		$room_ary['alert_text'] = $alert_text;
		return array("result"=>"0","operation"=>$operation,"data"=>$room_ary,"result_message"=>"进房询问");  
	}
	
	
	/*
		准备操作
	*/
	public function readyStart($arrData)
	{
		$data 			= $arrData['data'];
		$operation 		= $arrData['operation'];
		$account_id 	= $arrData['account_id'];
		$client_id 		= $arrData['client_id'];

		$session 		= $arrData['session'];
		$Verification_Model = Verification_Model::getModelObject();
		if(false == $Verification_Model->checkRequestSession($account_id,$session))
		{
			return OPT_CONST::NO_RETURN;
		}
		
		if(!isset($data['room_id']) || trim($data['room_id']) == G_CONST::EMPTY_STRING)
		{
			$this->logMessage('error', "function(readyStart):lack of room_id"." in file".__FILE__." on Line ".__LINE__);
			return $this->_missingPrameterArr($operation,"room_id");
		}
		
		$room_id = $data['room_id'];
		
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		
		//获取玩家当前状态，是否未准备
		$rStatus = $this->queryAccountStatus($room_id, $account_id);
		if(Redis_CONST::DATA_NONEXISTENT === $rStatus || !in_array($rStatus, [Game::AccountStatus_Initial, Game::AccountStatus_Notready])  )
		{
			//广播用户状态改变
			$this->updateAccountStatus($room_id, $account_id, $rStatus);
			return OPT_CONST::NO_RETURN;
		}
		
		
		//更新用户状态
		$rStatus = Game::AccountStatus_Ready;
		$this->updateAccountStatus($room_id, $account_id, $rStatus);

		$this->startGame($room_id);
		
		return OPT_CONST::NO_RETURN;
	}
	
	/*
		历史积分榜
	*/
	public function historyScoreboard($arrData)
	{
		$result = array();
		
		$data 			= $arrData['data'];
		$operation 		= $arrData['operation'];
		$account_id 	= $arrData['account_id'];
		$client_id 		= $arrData['client_id'];
		
		$session 		= $arrData['session'];
		$Verification_Model = Verification_Model::getModelObject();
		if(false == $Verification_Model->checkRequestSession($account_id,$session))
		{
			return OPT_CONST::NO_RETURN;
		}

		$MMYSQL = $this->initMysql();

		if(isset($data['room_number']))
		{
			$room_number = $data['room_number'];
			//判断房间申请记录是否存在
			$room_where = 'room_number="'.$room_number.'"';
			$room_sql = 'select room_id,account_id,is_close from '.Room.' where '.$room_where;
			$room_query = $MMYSQL->query($room_sql);
			if(!is_array($room_query) || count($room_query) == 0 )
			{
				$this->writeLog("function(lastScoreboard):room($room_number) not exist"." in file".__FILE__." on Line ".__LINE__);
				return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>$result,"result_message"=>"房间不存在");  
			}else{
				$room_id = $room_query[0]['room_id'];
			}
		}
		else
		{
			if(!(isset($data['room_id'])&& $data['room_id'] > 0) )
			{
				$this->logMessage('error', "function(historyScoreboard):lack of room_id"." in file".__FILE__." on Line ".__LINE__);
				return $this->_missingPrameterArr($operation,"room_id");
			}
			$room_id = $data['room_id'];
		}
		
		$scoreboards = array();

		$sql = 'select * from room_scoreboard where room_id='.$room_id.' and game_type='.Game::Game_Type.' order by create_time desc limit 10';
		$query = $MMYSQL->query($sql);
		if(!is_array($query) )
		{
			$this->writeLog("function(historyScoreboard):room($room_id) not exist"." in file".__FILE__." on Line ".__LINE__);
		}else{
			foreach ($query as $row) {

				$name_board = array();
				$scoreboard = json_decode($row['board']);
				$create_time = $row['create_time'];
				
				if($scoreboard){
					foreach ($scoreboard as $account_id => $score) {
						$account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
						$name = $MMYSQL->single($account_sql);
						$name_board[] = array('name'=>$name, 'score'=>$score);
					}
					$scoreboards[] = array('time'=>$create_time, 'scoreboard'=>$name_board);
				}
			}
		}
		
		return array("result"=>"0","operation"=>$operation,"data"=>$scoreboards,"result_message"=>"历史积分榜");  
	}
    public function closeRoom($arrData)
    {
        $operation = $arrData['operation'];
        $data = $arrData['data'];
        $account_id = $arrData['account_id'];
        $room_number = $data['room_number'];



        // $current_timer_id = $this->queryTimerId($room_id);
        // if($current_timer_id == $timer_id){
        // 	$this->updateTimer($room_id, -1);
        // } else {
        // 	//timer对不上，返回
        // 	$this->writeLog("function(clearRoomPassive):timer对不上($current_timer_id != $timer_id)"." in file".__FILE__." on Line ".__LINE__);
        // 	return false;
        // }

        //判断是否全部人离线
        //$clients_of_groupid = Gateway::getClientSessionsByGroup($room_id);
        //if(count($clients_of_groupid) > 0){
        //    $this->writeLog("function(clearRoomPassive):房间($room_id)有人不清理");
        //    return false;
        //}

        $MMYSQL = $this->initMysql();

        $room_where = 'room_number='.$room_number.' and is_close =0';
        $room_sql = 'select room_id,account_id,is_close from '.Room.' where '.$room_where;
        $room_query = $MMYSQL->query($room_sql);
        if(!is_array($room_query) || count($room_query) == 0 )
        {
            $this->writeLog("function(closeRoomManager):room($room_number) not exist"." in file".__FILE__." on Line ".__LINE__);
            return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>[],"result_message"=>"房间不存在");
        }else{
            $room_id = $room_query[0]['room_id'];
        }

        if ($room_query[0]['account_id'] != $account_id){
            $this->writeLog("function(closeRoomManager):room($room_number) no auth"." in file".__FILE__." on Line ".__LINE__);
            return array("result"=>OPT_CONST::FAILED,"operation"=>$operation,"data"=>[],"result_message"=>"不是管理员，不能关闭房间");
        }

        $this->writeLog("[$room_id] 触发群主清房间");

        $Redis_Model = Redis_Model::getModelObject();
        $replyArr = array("[roomid]"=>$room_id);
//        $RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);

        $game_num = $this->queryGameNumber($room_id);
        $creator = $this->queryCreator($room_id);
        if(Config::Ticket_Mode==2 && $game_num==0 && $creator>0){
            $spend_ticket_count = $this->queryTicketCount($room_id);
            $this->balanceTicket($room_id, $creator, - $spend_ticket_count);
        }

        //保存积分榜
        if($game_num > 0){
            $Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
            $round = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameRound, 1);
            $this->writeLog("[$room_id] 第".($round-1)."轮 结束!");

            $setting = $this->queryRoomSetting($room_id);
            //$round = $setting['ground'];
            $game_info['room_id'] = $room_id;
            $game_info['game_type'] = Game::Game_Type;
            $game_info['dealer_num'] = Config::Dealer_Num;
            $game_info['round'] = $round-1;

            $scoreboard = array();
            if(isset($setting['scoreboard']) && $setting['scoreboard']){
                $board_json_str = $setting['scoreboard'];
                $scoreboard = json_decode($board_json_str, true); //转为关联数组
            } else {
                //积分榜为空
                $scoreboard = array();
                $board_json_str = "";
            }

            $ticket_checked_user = $this->queryTicketCheckedUser($room_id);
            foreach ($scoreboard as $key => $value) {
                if(!in_array($key, $ticket_checked_user)){
                    //未扣房卡的用户不显示在积分榜上
                    unset($scoreboard[$key]);
                }
            }
            $save_scoreboard = $scoreboard;

            $banker_id = $this->queryBanker($room_id);
            $banker_score = $this->queryBankerScore($room_id);

            foreach ($scoreboard as $account_id => $score) {
                $account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
                $name = $MMYSQL->single($account_sql);
                if($banker_id == $account_id)
                {
                    $score -= $banker_score;
                    $save_scoreboard[$account_id] = $score;
                }
            }

            $board_json_str = json_encode($save_scoreboard);

            $name_board = array();
            foreach ($save_scoreboard as $account_id => $score) {
                $account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
                $name = $MMYSQL->single($account_sql);
                $name_board[] = array('name'=>$name, 'score'=>$score, 'account_id'=>$account_id);
            }

            //规则文本
            $rule_text = $this->formatRuleText($room_id);
            $balance_scoreboard = array('time'=>time(), 'scoreboard'=>$name_board,'game_num'=>$game_num);
            $balance_board_json_str = json_encode($balance_scoreboard['scoreboard']);

            $start_time = isset($setting[Redis_Const::Room_Field_StartTime])?$setting[Redis_Const::Room_Field_StartTime]:1;

            $board_array['start_time'] = $start_time;
            $board_array['create_time'] = time();
            $board_array['is_delete'] = G_CONST::IS_FALSE;
            $board_array['game_type'] = Game::Game_Type;
            $board_array['room_id'] = $room_id;
            $board_array['round'] = $round - 1;
            $board_array['game_num'] = $game_num;
            $board_array['rule_text'] = $rule_text;
            $board_array['board'] = $board_json_str;
            $board_array['balance_board'] = $balance_board_json_str;
            $board_id = $MMYSQL->insertReturnID(Room_Scoreboard,$board_array);

            //保存用户积分
            $game_info['score_board'] = $save_scoreboard;
            $this->saveAccountGameScore($game_info);
        }
//        $scoreboard = $this->getScoreBoard($room_id);
//        $this->pushMessageToGroup($room_id,$scoreboard);
        Gateway::closeCurrentClient();
        $client_list = Gateway::getClientInfoByGroup($room_id);
        foreach ($client_list as $client_id=>$item) {
            Gateway::closeClient($client_id);
        }
        //清理房间
        $this->initRoomData($room_id);

        return true;
    }
}